﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Threading;
using JigLibX.Physics;
using JigLibX.Collision;
using JigLibX.Geometry;
using Microsoft.Xna.Framework.Input.Touch;
using Services;
using Utilities;
using WAS.Menu;
using Microsoft.Phone.Shell;

namespace WAS.Logic.SampleLevel
{
    using Nuke = Projectile;
    using NukeData = ProjectileData;

    public class SquashingLayer : GamePlayLayer
    {
        float time_to_next_spawn = 0;
        Vector3 startPoint;
        Vector3 destinationPoint;
        float[] level_chance = { 50, 62.5f, 75, 81.25f, 87.5f, 93.75f, 100 };
        float n;
        bool resume_state;
        public float Actual_Total_Game_Time = 0;
        public float Total_Game_time;

        AudioManager audio_manager;
        public SquashingLayer(Game game, BaseLevelStats current_score, int num_lives, bool resume_state)
            : base(game, current_score, num_lives)
        {
            this.resume_state = resume_state;
        }
        
        public override void Initialize()
        {
            base.Initialize();
        }

        protected override void LoadContent()
        {
            base.LoadContent();
        }

        protected override void start_level()
        {
            //PhoneApplicationService.Current.Closing += new EventHandler<ClosingEventArgs>(Current_Closing);
            PhoneApplicationService.Current.Deactivated += new EventHandler<DeactivatedEventArgs>(Current_Deactivated);
            random = new Random();
            /// Inizializziamo la fisica.
            physics = new PhysicsSystem()
            {
                CollisionSystem = new CollisionSystemSAP() { UseSweepTests = true },
                Gravity = Vector3.Zero,

                NumCollisionIterations = 2, //8
                NumContactIterations = 2, //8
                NumPenetrationRelaxtionTimesteps = 5, //15
            };

            StructAllocatorManager.Reset();

            var entry = Leaderboard.GetWakaModeStats();

            if (!resume_state)
            {
                CurrentState = new State()
                {
                    asteroids = new ArrayList<Asteroid>(35),
                    enemies = new ArrayList<Ship>(15),
                    bosses = new ArrayList<Ship>(5),
                    shockwaves = new ArrayList<ShockWave>(5),
                    bonuses = new ArrayList<Bonus>(5),
                    level = 0,
                    time_to_next_level = 0
                };
            }
            else
            {
                CurrentState = new State()
                {
                    asteroids = new ArrayList<Asteroid>(35),
                    enemies = new ArrayList<Ship>(15),
                    bosses = new ArrayList<Ship>(5),
                    shockwaves = new ArrayList<ShockWave>(5),
                    bonuses = new ArrayList<Bonus>(5),
                    level = entry.Level,
                    //time_to_next_level = entry.TimeToEndGame,
                    time_to_add_or_remove = entry.TimeToAddOrRemove,
                    num_of_asteroids_hit = entry.AsteroidHits
                };
                current_score.BossDestroyed = entry.BossDestroyed;
                current_score.ShipsDestroyed = entry.ShipsDestroyed;
                current_score.TimeToEndGame = entry.TimeToEndGame;
                
            }

            scene_bs = new BoundingSphere(Vector3.Zero, 5f);

            Total_Game_time = entry.TotalGameTime;

            NewExplosions = new ArrayList<Explosion>(25);
            NewShockWaves = new ArrayList<ShockWave>(5);
            effects_manager = Game.Services.GetService(typeof(EffectsManager)) as EffectsManager;
            audio_manager = Game.Services.GetService(typeof(IAudioManager)) as AudioManager;

                    
        }

        

        

        protected override void OnEnabledChanged(object sender, EventArgs args)
        {
            base.OnEnabledChanged(sender, args);
        }

        public override void Update(GameTime gameTime)
        {
            var s = CurrentState;            
            var dt = (float)gameTime.ElapsedGameTime.TotalSeconds * s.slow_motion;
            
            //e' terribile ma vista l'ora me lo posso permettere :P
            Actual_Total_Game_Time += dt;
            s.totalgametime += dt;

            if (resume_state == true)
            {
                if (CurrentState.level >= 1 && CurrentState.level < 4)
                {
                    audio_manager.OnMusicaBaseBegin(2);
                }
                else
                    if (CurrentState.level >= 4 && CurrentState.level < 7)
                    {
                        audio_manager.OnMusicaIntermediaBegin(2);
                    }
                    else
                        audio_manager.OnMusicaDinamicaBegin(2);
                resume_state = false;
            }

            //se e' in trial controllo se e' ancora valida la copia
            if (Game.IsTrial() && Game.IsTrialExpired(Actual_Total_Game_Time + Total_Game_time))
            {
                this.Enabled = false;
                audio_service.stopAllSounds();
                ForceLose();
            }

            if (CurrentScore.TimeToEndGame + CurrentState.time_to_add_or_remove> 0)
            {
                
                if (s.time_to_next_level <= 0.0)
                {
                    s.level++;
                    
                    s.time_to_next_level = State.TIME_FOR_LEVEL + (10 * s.level);
                    if (s.level == 1)
                        audio_manager.OnMusicaBaseBegin(2);
                    if (s.level == 4)
                        audio_manager.OnMusicaIntermediaBegin(2);
                    if (s.level == 7)
                        audio_manager.OnMusicaDinamicaBegin(2);
                }

                if (CurrentState.time_to_add_or_remove != 0.0)
                {
                    var c = CurrentScore;
                    if (CurrentState.time_to_add_or_remove > 0.0)
                    {
                        
                            if (c.TimeToEndGame + (CurrentState.enemies.Count * 3 * dt) <= c.TimeToEndGame + CurrentState.time_to_add_or_remove &&
                               c.TimeToEndGame + CurrentState.time_to_add_or_remove < 30.0)
                            {
                                c.TimeToEndGame += ((2 * dt) + (CurrentState.enemies.Count * 3 * dt));
                                CurrentState.time_to_add_or_remove -= (dt + (CurrentState.enemies.Count * 3 * dt));
                            }
                            else
                            {
                                c.TimeToEndGame += ((2 * dt) + (CurrentState.enemies.Count * dt));
                                CurrentState.time_to_add_or_remove -= (dt + (CurrentState.enemies.Count * dt));
                            }
                        
                    }
                    else 
                    {

                        //CurrentState.time_to_add_or_remove e' negativo
                        c.TimeToEndGame += CurrentState.time_to_add_or_remove;
                        CurrentState.time_to_add_or_remove = 0.0f;
                    }
                    CurrentScore = c;
                }

                if (CurrentState.enemies.Count <= 14 &&  
                    time_to_next_spawn <= 0)
                {

                    startPoint = generateInViewportRandomPoint();
                    destinationPoint = generateDestinationPoint(startPoint);
                    ShipType ship_type_to_add;
                    if (CurrentState.level < 8)
                        n = (float)random.NextDouble() * level_chance[CurrentState.level - 1];
                    else
                        n = (float)random.NextDouble() * level_chance[6];
                    if (n < 25.5)
                        ship_type_to_add = (ShipType)6;
                    else if (n >= 25.0 && n < 50.0)
                        ship_type_to_add = (ShipType)7;
                    else if (n >= 50 && n < 75)
                        ship_type_to_add = (ShipType)8;
                    else if (n >= 75 && n < 87.5 && s.slow_motion_timer == 0)
                        ship_type_to_add = (ShipType)9;
                    else if(s.slow_motion_timer== 0)
                        ship_type_to_add = (ShipType)10;
                    else
                        ship_type_to_add = (ShipType)8;

                    var ship_to_add = generate_enemie(startPoint, ship_type_to_add ,destinationPoint);

                    if (CurrentState.slow_motion_timer == 0)
                        audio_manager.OnWarp(1);
                    else 
                        audio_manager.OnWarp(3);
                    warps.Add(new EffectsManager.EnemyWarp(effects_manager, ship_to_add));
                    CurrentState.enemies.Add(ship_to_add);
                    time_to_next_spawn = (float) ((-Math.Atan(s.level/3-1)+MathHelper.PiOver2) + (random.NextDouble()) *  (-Math.Atan(s.level/3-1)+MathHelper.PiOver2));
                }

                //Generazione di Asteroidi, attualmente 4 volte il livello
                if (CurrentState.asteroids.Count <= 35 &&
                    CurrentState.asteroids.Count <= s.level *  4)
                {
                    generateRandomAsteroid(100, 200, s.level);
                }

                for (int i = 0; i < CurrentState.enemies.Count; i++)
                {
                    var c = CurrentState.enemies[i];
                    if (c.is_warp_running)
                    {
                        c.time_to_finish_warp -= dt;
                        if (c.time_to_finish_warp <= 0.0)
                        {
                            c.is_warp_running = false;

                            var startPoint = generateInViewportRandomPoint();
                            c.geometry.Position = startPoint;
                            c.direction = generateDestinationPoint(startPoint);

                            warps.Add(new EffectsManager.EnemyWarp(effects_manager, c));
                        }
                    }
                }
                for (int i = 0; i < warps.Count; i++)
                {
                    if (warps[i].warping_out_timer <= 0)
                    {
                        warps[i].particle.IsActive = false;
                        warps.RemoveAt(i);
                        i--;
                    }
                    else
                        warps[i].Update(dt);
                }

                time_to_next_spawn -= dt;
                s.time_to_next_level -= dt;
                if (CurrentScore.ShipsDestroyed % 50 == 0)
                    GC.Collect();
            }
            else
            {
                this.Enabled = false;
            }
            //// Aggiorniamo il timer di slow-motion

            CurrentState.slow_motion_timer = Math.Max(0.0f, CurrentState.slow_motion_timer -
            (float)gameTime.ElapsedGameTime.TotalSeconds);

            CurrentState.allert_motion_timer = Math.Max(0.0f, CurrentState.allert_motion_timer -
            (float)gameTime.ElapsedGameTime.TotalSeconds);

            CurrentState.buzz_motion_timer = Math.Max(0.0f, CurrentState.buzz_motion_timer -
            (float)gameTime.ElapsedGameTime.TotalSeconds);

            base.Update(gameTime);
        }

        public void ForceLose()
        {
            current_score.TimeToEndGame = 0.0f;
            LevelLost();
        }

        //void Current_Closing(object sender, ClosingEventArgs e)
        //{
        //    if(current_score.TimeToEndGame > 0)
        //        Leaderboard.SaveWakaModeStats(new WakaShipModeEntry()
        //        {
        //            TimeToEndGame = current_score.TimeToEndGame,
        //            BossDestroyed = current_score.BossDestroyed,
        //            ShipsDestroyed = current_score.ShipsDestroyed,
        //            LevelScore = current_score.LevelScore,
        //            Level = CurrentState.level,
        //            AudioState = AudioManager.Volume > 0,
        //            AsteroidHits = CurrentState.num_of_asteroids_hit,
        //            TimeToAddOrRemove = CurrentState.time_to_add_or_remove,
        //            FirstTimePlay = false
        //        }
        //        );
        //    else
        //        Leaderboard.SaveWakaModeStats(new WakaShipModeEntry()
        //        {
        //            TimeToEndGame = 0,
        //            BossDestroyed = 0,
        //            ShipsDestroyed = 0,
        //            LevelScore = 0,
        //            Level = 0,
        //            AudioState = AudioManager.Volume > 0,
        //            AsteroidHits = 0,
        //            TimeToAddOrRemove = 0,
        //            FirstTimePlay = false
        //        }
        //      ); 
        //}
        void Current_Deactivated(object sender, DeactivatedEventArgs e)
        {
            var tmp = Leaderboard.GetWakaModeStats();
            if (current_score.TimeToEndGame > 0)
                Leaderboard.SaveWakaModeStats(new WakaShipModeEntry()
                {
                    TimeToEndGame = current_score.TimeToEndGame,
                    BossDestroyed = current_score.BossDestroyed,
                    ShipsDestroyed = current_score.ShipsDestroyed,
                    LevelScore = current_score.LevelScore,
                    Level = CurrentState.level,
                    AudioState = AudioManager.Volume > 0,
                    AsteroidHits = CurrentState.num_of_asteroids_hit,
                    TimeToAddOrRemove = CurrentState.time_to_add_or_remove,
                    showAlwaysTutorial = tmp.showAlwaysTutorial,
                    TotalGameTime = tmp.TotalGameTime + Actual_Total_Game_Time
                }
            );
            else
            {
                Leaderboard.SaveWakaModeStats(new WakaShipModeEntry()
                {
                    TimeToEndGame = 0,
                    BossDestroyed = 0,
                    ShipsDestroyed = 0,
                    LevelScore = 0,
                    Level = 0,
                    AudioState = AudioManager.Volume > 0,
                    AsteroidHits = 0,
                    TimeToAddOrRemove = 0,
                    showAlwaysTutorial = tmp.showAlwaysTutorial,
                    TotalGameTime = tmp.TotalGameTime + Actual_Total_Game_Time
                }
              );
            }
        }

    }
}
